package edu.ubb.remeye.security.util.des;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

import edu.ubb.remeye.exception.DESSecurityException;
import edu.ubb.remeye.gui.internationalization.LanguageManager;

/**
 * DES encrypter class for String encryption, decryption and key generation.
 * 
 * @author Andrew Ianicicau
 *
 */
public class DESEncrypter {
	
	///////////////////////////////////////////////////////////////////////////////////
	////		METHODS - ESEncrypter
	///////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * Method for SecretKey generation used for encryption, decryption.
	 * @return SecretKey used for encryption, decryption.
	 * @throws DESSecurityException
	 */
	public static SecretKey generateSecretKey() throws DESSecurityException {
		SecretKey secretKey = null;
		try {
			KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
			secretKey = keyGenerator.generateKey();
		} catch (NoSuchAlgorithmException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		}
		return secretKey;
	}
	
	/**
	 * Converts the SecretKey into an array of bytes.
	 * @param key SecretKey to convert.
	 * @return SecretKey converted to byte array.
	 */
	public static byte[] getSecretKeyBytes(SecretKey key) {
		byte[] keyBytes = key.getEncoded();
		return keyBytes;
	}
	
	/**
	 * Converts SecretKey byte array back to SecretKey.
	 * @param secretBytes SecretKey byte array.
	 * @return SecretKey from byte array.
	 * @throws DESSecurityException
	 */
	public static SecretKey getSecretKeyFromBytes(byte[] secretBytes) throws DESSecurityException {
		SecretKey secretKey = null;
		try {
			KeySpec keySpec = new DESKeySpec(secretBytes);
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			secretKey = keyFactory.generateSecret(keySpec);
		} catch (InvalidKeyException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (NoSuchAlgorithmException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (InvalidKeySpecException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		}
		return secretKey;
	}
	
	/**
	 * Encryption of the given string using the given key.
	 * @param str The string to encrypt.
	 * @param key Key for encryption.
	 * @return The encrypted string or null.
	 * @throws DESSecurityException 
	 */
	public static String encrypt(String str, SecretKey key) throws DESSecurityException {
		String encoded = null;
		
		try {
			Cipher encCipher = Cipher.getInstance("DES");
			encCipher.init(Cipher.ENCRYPT_MODE, key);
			
			// Encode the string into bytes using utf-8
			byte[] utf8 = str.getBytes("UTF8");
			
			// Encrypt
	        byte[] enc = encCipher.doFinal(utf8);
	        
	        // Encode bytes to base64 to get a string
	        encoded = new String(biz.source_code.base64Coder.Base64Coder.encode(enc));
		} catch (NoSuchAlgorithmException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (NoSuchPaddingException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (InvalidKeyException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (UnsupportedEncodingException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (IllegalBlockSizeException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (BadPaddingException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		}	
        
        return encoded;
	}
	
	/**
	 * Decryption of the given string, using the key.
	 * @param str The string to decrypt.
	 * @param key Key for decryption.
	 * @return The decrypted string or null.
	 * @throws DESSecurityException 
	 */
	public static String decrypt(String str, SecretKey key) throws DESSecurityException {
		String decoded = null;
		
		try {
			Cipher decCipher = Cipher.getInstance("DES");
			decCipher.init(Cipher.DECRYPT_MODE, key);
			
			// Decode base64 to get bytes
	        byte[] dec = biz.source_code.base64Coder.Base64Coder.decode(str);

	        // Decrypt
	        byte[] utf8 = decCipher.doFinal(dec);

	        // Decode using utf-8
	        decoded =  new String(utf8, "UTF8");
		} catch (InvalidKeyException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (NoSuchAlgorithmException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (NoSuchPaddingException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (IllegalBlockSizeException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (BadPaddingException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		} catch (UnsupportedEncodingException e) {
			String errorMessage = LanguageManager.getLanguageManager().getText("desfailure");
			throw new DESSecurityException(errorMessage);
		}
        
        return decoded;
	}
	
}
